﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;

namespace FerrSimplicity
{
    /// <summary>
    /// THis component draws a 2D sprite at the object's location
    /// </summary>
    public class ComSprite2D : BaseComponent, IColorTweenable
    {
        #region Fields
        /// <summary>
        /// Name of the image, so we can load it in the LoadContent method
        /// </summary>
        protected string    mImageName;
        /// <summary>
        /// Texture itself! yay?
        /// </summary>
        protected Texture2D mImage;
        #endregion

        #region Properties
        /// <summary>
        /// Returns the width of the sprite's image, including the parent's scale
        /// </summary>
        public int Width
        {
            get { if (Source != null) return (int)(Source.Value.Width  * Parent.Transform.ScaleSc); if (mImage != null) return (int)(mImage.Width  * Parent.Transform.ScaleSc); return 0; }
        }
        /// <summary>
        /// Returns the height of the sprite's image, including the parent's scale
        /// </summary>
        public int Height
        {
            get { if (Source != null) return (int)(Source.Value.Height * Parent.Transform.ScaleSc); if (mImage != null) return (int)(mImage.Height * Parent.Transform.ScaleSc); return 0; }
        }
        /// <summary>
        /// Returns a new rectangle describing the bounds of this image in world coordinates
        /// </summary>
        public Rectangle Bounds
        {
            get { return new Rectangle((int)(Parent.Transform.Position.X - Origin.X * Parent.Transform.ScaleSc), (int)(Parent.Transform.Position.Y - Origin.Y * Parent.Transform.ScaleSc), Width, Height); }
        }
        /// <summary>
        /// The color tint of the object, done as a multiply. Default color is Color.White
        /// </summary>
        public Color   Tint   { get; set; }
        /// <summary>
        /// By default, this is (-inf,-inf) and LoadContent will adjust this to the center of the image if it
        /// has not changed. If you change the origin, this component will not adjust the origin for you.
        /// </summary>
        public Vector2 Origin { get; set; }
        /// <summary>
        /// Setting the value of this property will load a new image, if one is already loaded. Otherwise, it just sets
        /// the name for loading later. If replacing an existing image, this will reset the origin of the sprite
        /// </summary>
        public string Image
        {
            get { return mImageName; }
            set 
            { 
                mImageName = value;
                if (mImage != null)
                {
                    Origin = new Vector2(float.NegativeInfinity, float.NegativeInfinity);
                    LoadImage();
                }
            }
        }
        /// <summary>
        /// The source region of the texture to pull the sprite from
        /// </summary>
        public Rectangle? Source { get; set; }
        #endregion

        #region Constructors
        /// <summary>
        /// A default parameterless constructor for use with cloning
        /// </summary>
        public ComSprite2D()
            : this("") { }
        /// <summary>
        /// Basic constructor, copies values
        /// </summary>
        /// <param name="aImage">Name of the image resource to use</param>
        public ComSprite2D(string aImage                                                  )
            : this(aImage, Color.White, new Vector2(float.NegativeInfinity, float.NegativeInfinity), null   ) { }
        /// <summary>
        /// Basic constructor, copies values
        /// </summary>
        /// <param name="aImage">Name of the image resource to use</param>
        /// <param name="aSource">If you want to specify a specific section of a spritesheet, rather than an entire file.</param>
        public ComSprite2D(string aImage,                               Rectangle? aSource)
            : this(aImage, Color.White, new Vector2(float.NegativeInfinity, float.NegativeInfinity), aSource) { }
        /// <summary>
        /// Basic constructor, copies values
        /// </summary>
        /// <param name="aImage">Name of the image resource to use</param>
        /// <param name="aTint">Color the object should be tinted, multiplied in</param>
        public ComSprite2D(string aImage, Color aTint                                     )
            : this(aImage, aTint, new Vector2(float.NegativeInfinity, float.NegativeInfinity),       null   ) { }
        /// <summary>
        /// Basic constructor, copies values
        /// </summary>
        /// <param name="aImage">Name of the image resource to use</param>
        /// <param name="aTint">Color the object should be tinted, multiplied in</param>
        /// <param name="aSource">If you want to specify a specific section of a spritesheet, rather than an entire file.</param>
        public ComSprite2D(string aImage, Color aTint,                  Rectangle? aSource)
            : this(aImage, aTint,       new Vector2(float.NegativeInfinity, float.NegativeInfinity), aSource) { }
        /// <summary>
        /// Basic constructor, copies values
        /// </summary>
        /// <param name="aImage">Name of the image resource to use</param>
        /// <param name="aTint">Color the object should be tinted, multiplied in</param>
        /// <param name="aOrigin">The location the object should be rotated around, and centered on, this defaults to the center of the sprite unless specified here.</param>
        public ComSprite2D(string aImage, Color aTint, Vector2 aOrigin                    )
            : this(aImage, aTint,       aOrigin,                                                     null   ) { }
        /// <summary>
        /// Basic constructor, copies values
        /// </summary>
        /// <param name="aImage">Name of the image resource to use</param>
        /// <param name="aTint">Color the object should be tinted, multiplied in</param>
        /// <param name="aOrigin">The location the object should be rotated around, and centered on, this defaults to the center of the sprite unless specified here.</param>
        /// <param name="aSource">If you want to specify a specific section of a spritesheet, rather than an entire file.</param>
        public ComSprite2D(string aImage, Color aTint, Vector2 aOrigin, Rectangle? aSource)
        {
            mImageName = aImage;
            Source     = aSource;
            Origin     = aOrigin;
            Tint       = aTint;
        }
        #endregion

        #region Overrides
        public override void LoadContent()
        {
            // load the image as appropriate
            LoadImage();

            //make a call to the parent's LoadGraphicsContent, so it can do what it needs to
            base.LoadContent();
        }
        public override void Draw       (GameTime gameTime)
        {
            // some quick error checking
            if (mImage == null)
                throw new Exception("ComDraw2D's LoadContent was not called, or texture was not loaded properly!");
            if (FerrGlobals.SpriteBatch == null)
                throw new Exception("You need to set FerrGlobals.SpriteBatch to a valid SpriteBatch object!");

            FerrGlobals.SpriteBatch.Draw(mImage, Parent.Transform.Position2D, Source, Tint, Parent.Transform.Rotation2D, Origin, Parent.Transform.ScaleSc, SpriteEffects.None, Parent.Transform.Position.Z);

            base.Draw(gameTime);
        }
        #endregion

        #region Methods
        /// <summary>
        /// Used for loading the image. Wrapped into it's own function because it can be called
        /// from multiple different locations
        /// </summary>
        protected void LoadImage()
        {
            // load the image
            mImage = Parent.Game.Content.Load<Texture2D>(mImageName);

            // if the user has not set the origin already, we'll set it ourselves
            if (Origin.X == float.NegativeInfinity && Origin.Y == float.NegativeInfinity)
            {
                // the center of the image is the size of the image, or source, divided in half
                if (Source != null)
                {
                    Origin = new Vector2(Source.Value.Width / 2, Source.Value.Height / 2);
                }
                else
                {
                    Origin = new Vector2(mImage.Width / 2, mImage.Height / 2);
                }
            }
        }
        #endregion
    }
}
